module cdc_syncfifo #(parameter DATA_WIDTH = 8)
(  
  // Write clk interface  
  input  [DATA_WIDTH-1:0] wdata,
  output                  wrdy,
  input                   wput,
  input                   wclk, 
  input                   wrst_n,  
  // Read clk interface  
  output [DATA_WIDTH-1:0] rdata,  
  output                  rrdy,  
  input                   rget,
  input                   rclk, 
  input                   rrst_n
);

wire wptr, we, wq2_rptr;  
wire rptr, rq2_wptr;  

wctl wctl (  
  .wrdy      (wrdy),
  .wptr      (wptr),
  .we        (we),
  .wput      (wput),
  .wq2_rptr  (wq2_rptr),
  .wclk      (wclk),
  .wrst_n    (wrst_n)
);  

rctl rctl(
  .rrdy      (rrdy),
  .rptr      (rptr),
  .rget      (rget),
  .rq2_wptr  (rq2_wptr),
  .rclk      (rclk),
  .rrst_n    (rrst_n)
);  
sync2 w2r_sync (.q(rq2_wptr), .d(wptr), .clk(rclk), .rst_n(rrst_n));  
sync2 r2w_sync (.q(wq2_rptr), .d(rptr), .clk(wclk), .rst_n(wrst_n));  

// dual-port 2-deep ram  
dp_ram2 #(.DATA_WIDTH(DATA_WIDTH)) dpram (.q(rdata), .d(wdata),
                                          .waddr(wptr), .raddr(rptr),
                                          .we(we), .clk(wclk), .*);
                      
endmodule


module sync2 (
  output q,  
  input  d, clk, rst_n);

reg q1; 

// 1st stage ff output  
always_ff @(posedge clk or negedge rst_n)
  if (!rst_n) {q,q1} <= '0;
  else 
    {q,q1} <= {q1,d};

endmodule

module wctl (  
  output     wrdy,
  output reg wptr,
  output     we,  
  input      wput, 
  input      wq2_rptr,  
  input      wclk,
  input      wrst_n
);  

assign we    = wrdy & wput;  
assign wrdy  = ~(wq2_rptr ^ wptr);  
always_ff @(posedge wclk or negedge wrst_n)    
  if (!wrst_n) 
    wptr <= '0;    
  else 
    wptr <= wptr ^ we;

endmodule

module rctl (
  output     rrdy,
  output reg rptr,  
  input      rget,
  input      rq2_wptr,  
  input      rclk,
  input      rrst_n
);  

typedef enum {xxx, VALID} status_e;  

status_e status;
assign status = status_e'(rrdy);  
assign rinc  = rrdy & rget;  
assign rrdy  = (rq2_wptr ^ rptr);  
always_ff @(posedge rclk or negedge rrst_n) 
  if   (!rrst_n) 
    rptr <= '0;
  else
    rptr <= rptr ^ rinc;
  
endmodule

module dp_ram2 #(parameter DATA_WIDTH = 8)(
  output [DATA_WIDTH-1:0] q,
  input  [DATA_WIDTH-1:0] d,
  input  waddr, raddr, we, clk
);  

wire [DATA_WIDTH-1:0] mem [0:1];  
always_ff @(posedge clk)    
  if (we) 
    mem[waddr] <= d;  
  
assign q = mem[raddr];
  
endmodule

